/*
Save the screen to PCX file
*/

#include <plib.h>
#include <wlib.h>

#define BUFLEN 256

GLREF_D WSERV_SPEC *wserv_channel;

LOCAL_D VOID *fcb;
LOCAL_D UBYTE *pbuf;
LOCAL_D UBYTE *pobuf;
LOCAL_D UBYTE obuf[BUFLEN];

LOCAL_C VOID FlushBuffer(VOID)
    {
    f_write(fcb,&obuf[0],pobuf-&obuf[0]);
    pobuf=&obuf[0];
    }

LOCAL_C VOID putb(INT b)
    {
    *pobuf++=b;
    if (pobuf==&obuf[BUFLEN])
        FlushBuffer();
    }

LOCAL_C INT rev(INT dat)
    {
    INT i;
    INT rdat;

    rdat=0;
    for (i=0;i<8;i++)
        rdat|=((dat>>i)&1)<<(7-i);
    return(rdat^0xff);
    }

LOCAL_C VOID WritePCXLine(UBYTE *buf,UINT len)
    {
    UBYTE *p;
    UINT end;
    UINT count;
    INT byte;

    p=buf;
    byte=*p++;
    count=1;
    do
        {
        end=(p==(&buf[0]+len));
        if (byte==*p && count<0x3f && !end)
            {
            count++;
            p++;
            }
        else
            {
            byte=rev(byte);
            if (count>1 || (byte&0xC0)==0xC0)
                putb(count+0xC0);
            putb(byte);
            byte=*p++;
            count=1;
            }
        } while (!end);
    }

LOCAL_C VOID WriteHeader(TEXT *name,UINT width,UINT height,UINT bytewid)
    {
    struct
        {
        UBYTE manuf;
        UBYTE hard;
        UBYTE encod;
        UBYTE bitpx;
        P_RECT rect;
        WORD hres;
        WORD vres;
        UBYTE clrma[48];
        UBYTE vmode;
        UBYTE nplanes;
        WORD bplin;
        UBYTE padding[60];
        } header;

    f_open(&fcb,name,P_FREPLACE|P_FSTREAM|P_FUPDATE);
    p_bfil(&header,sizeof(header),0);
    header.manuf=10;
    header.hard=3;
    header.encod=TRUE;
    header.bitpx=1;
    header.rect.br.x=width-1;
    header.rect.br.y=height-1;
    header.hres=640;
    header.vres=480;
    header.nplanes=1;
    header.bplin=bytewid;
    f_write(fcb,&header,sizeof(header));
    }

#pragma save, ENTER_CALL

LOCAL_C INT WritePCXFile(TEXT *name)
    {
    UINT len;
    P_POINT size;
    P_POINT line;

    size=wserv_channel->conn.info.pixels;
    len=((size.x+15)>>3)&~1;
    WriteHeader(name,size.x,size.y,len);
    pbuf=f_alloc(len);
    line.x=0;
    for (line.y=0;line.y<size.y;line.y++)
        {
        gPeekBit(0,&line,size.x,pbuf);
        WritePCXLine(pbuf,len);
        }
    FlushBuffer();
    return(0);
    }

#pragma restore

GLDEF_C INT pcxScreenSave(TEXT *name)
    {
    INT ret;

    fcb=NULL;
    pbuf=NULL;
    pobuf=&obuf[0];
    ret=p_enter2((VOID *)WritePCXFile,name);
    p_free(pbuf);
    p_close(fcb);
    return(ret);
    }
